package org.noote.libs.tcpip;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Locale;
import java.util.concurrent.LinkedBlockingQueue;

public class IPServer_ConnectedThread extends Thread {

	private InputStream mmInStream = null;
	private OutputStream mmOutStream = null;
	private Socket mSocket = null;
	private PrintWriter out = null;
	
	private IPEvent_Server _events = null;
	
	private final LinkedBlockingQueue<String> mQueue = new LinkedBlockingQueue<String>();

	public IPServer_ConnectedThread(Socket socket, IPEvent_Server events) {
		this.mSocket = socket;
		this._events = events;
		InputStream tmpIn = null;
		OutputStream tmpOut = null;

		_events.setThread(this);
		
		// Get the input and output streams, using temp objects because
		// member streams are final
		try {
			tmpIn = socket.getInputStream();
			tmpOut = socket.getOutputStream();
		} catch (IOException e) {
			_events.onError("ConnectedThread() : cannot get I/O handlers, catch IOException "+e.getMessage());
			return;
		}
		if(tmpIn == null || tmpOut==null)
		{
			_events.onError("ConnectedThread() : cannot get I/O handlers");
			return;
		}

		this.mmInStream = tmpIn;
		this.mmOutStream = tmpOut;
		try {
			mmOutStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		out = new PrintWriter(new BufferedWriter(
				new OutputStreamWriter(mmOutStream), 1024*32), true);
	}

	@Override
	public void run() {
		if(mmInStream == null || mmOutStream == null)
			return;
		
		try {
			mmOutStream.flush();
		} catch (IOException e) {
		}
		_events.onConnected();
    	
        BufferedReader in = new BufferedReader(new InputStreamReader(mmInStream));
    	String line = null;
        try {
			while ((line = in.readLine()) != null) {
				// have we a command or a result ?
				if(line.contains("#") && line.contains("$"))
				{
					int offset = 0;
					while(true)
					{
						int idx_start = line.indexOf("#", offset);
						if(idx_start == -1) break;
						int idx_end = line.indexOf("$", idx_start);
						if(idx_end == -1) break;
						offset = idx_end+1;
						
						_events.onCmd(line.substring(idx_start+1, idx_end));
					}
				}
				else // else it's only text...
				{
					_events.onText(line);						
				}
			}
		} catch (IOException e) {
			_events.onError("readLine() : I/O Exception " + e.toString());			
		}
		close();
    }
	
	public InetAddress getClientAddress()
	{
		if(this.mSocket != null)
			return this.mSocket.getInetAddress();
		return null;
	}

	/* Call this from the main Activity to send data to the remote device */
	public boolean sendQueued(String sMessage) {
		
		try {
			mQueue.put(sMessage);
			
			while(!mQueue.isEmpty())
			{
				String sMsg = mQueue.take();
				
				out.println(sMsg);
			}
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public boolean sendMessage(String sMessage) {
		return sendQueued(sMessage);
	}
	public boolean sendCommand(String sCmd, String sOp) {
		return sendMessage("#"+sCmd.toLowerCase(Locale.getDefault())+":"+sOp+"$");
	}

	
	/* Call this from the main Activity to shutdown the connection */
	public void close() {
		try {
			mSocket.close();
		} catch (IOException e) {
		}
		_events.onDisconnected();
	}
}
